package com.jfinal.ext.ueditor.service;

import com.jfinal.ext.ueditor.config.ImageUploadConfig;
import com.jfinal.ext.ueditor.result.ImageUploadResult;
import com.jfinal.ext.ueditor.result.UploadResult;
import com.jfinal.ext.ueditor.storage.FileStorageManager;
import com.jfinal.ext.ueditor.storage.IStorageManager;
import com.jfinal.ext.ueditor.storage.StorageResult;
import com.jfinal.ext.util.FormatUtil;
import com.jfinal.ext.util.ImageUtil;
import com.jfinal.kit.FileKit;
import com.jfinal.log.Log;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.NotNull;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author Timor
 * @version 1.0
 * @date 2023/03/16 10:40:49
 */
public class ThumbnailService {
    private static final Log LOG = Log.getLog(ThumbnailService.class);
    private final IStorageManager storageManager;


    public ThumbnailService() {
        this(new FileStorageManager());
    }

    public ThumbnailService(@NotNull IStorageManager storageManager) {
        this.storageManager = storageManager;
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


    public UploadResult generate(@NotNull File file,
                                 @NotNull ImageUploadConfig config) {

        if (!config.getCompressEnable()) {
            return UploadResult.success();
        }


        final String extension = FileKit.getFileExtension(file);

        // 不支持压缩该类型图片
        if (Arrays.stream(ImageIO.getWriterFormatNames()).noneMatch(extension::equals)) {
            LOG.warn("不支持压缩该类型图片：" + extension);
            return UploadResult.success();
        }


        final BufferedImage image;

        try {
            image = ImageIO.read(file);
        } catch (IOException e) {
            LOG.warn("读取图片失败：" + file, e);

            FileUtils.deleteQuietly(file);
            return UploadResult.failure("读取图片失败！");
        }


        final ImageUploadResult result = ImageUploadResult.success();

        result.setCompressed(compressImages(image, file, config));

        return result;
    }

    private Map<String, String> compressImages(@NotNull BufferedImage image,
                                               @NotNull File file,
                                               @NotNull ImageUploadConfig config) {
        final List<Integer> compressWidth = config.getCompressWidth();
        final List<Integer> compressHeight = config.getCompressHeight();

        final List<Integer> items;
        final float dividend;

        if (!compressWidth.isEmpty()) {
            items = compressWidth;
            dividend = image.getWidth();
        } else if (!compressHeight.isEmpty()) {
            items = compressHeight;
            dividend = image.getHeight();
        } else {
            LOG.debug("图片压缩配置为空！");
            return Collections.emptyMap();
        }


        final Map<String, String> infos = new HashMap<>(items.size());

        items.forEach(item -> {
            final float rate = (float) item / dividend;

            final Map.Entry<String, String> entry =
                    compressImage(image, rate, file, config);

            if (null != entry) {
                infos.put(entry.getKey(), entry.getValue());
            }
        });

        return infos;
    }

    private Map.Entry<String, String> compressImage(
            @NotNull BufferedImage image, float rate,
            @NotNull File file, @NotNull ImageUploadConfig config) {

        if (rate < 0 || rate > 1) {
            return null;
        }


        final BufferedImage compressedImg =
                ImageUtil.compress(image, rate, config.getCompressScale());

        final String extension = FileKit.getFileExtension(file);
        final String fileName = file.getName()
                .substring(0, file.getName().length() - extension.length() - 1);

        final String suffix = toSuffix(compressedImg.getWidth(), compressedImg.getHeight());


        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

        try {
            if (!ImageIO.write(compressedImg, extension, stream)) {
                return Map.entry(suffix, "");
            }

        } catch (IOException e) {
            LOG.warn("写出缩略图失败", e);
            return Map.entry(suffix, "");
        }


        final String path = FormatUtil.parse(config.getPathFormat(), Map.of(
                FormatUtil.FILE_NAME, fileName,
                FormatUtil.FILE_TYPE, extension,
                FormatUtil.PREFIX, "",
                FormatUtil.SUFFIX, "_" + suffix));

        final StorageResult ret = storageManager.saveBinaryFile(stream.toByteArray(), path);

        if (ret.isFail()) {
            return Map.entry(suffix, "");
        }

        return Map.entry(suffix, ret.getUrl());
    }

    private String toSuffix(long width, long height) {
        return "%dx%d".formatted(width, height);
    }

}
